package aos.voting.entity;

import java.io.File;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Scanner;
import java.util.StringTokenizer;
import java.util.Vector;

import aos.voting.exception.AosException;
import aos.voting.log.LogUtils;

public class Configuration {

	private int ns;
	private int nc;
	private int m;
	private int timeUnit;
	private Vector<Integer> failNodes;
	private HashMap<Integer, String> id2Ip;
	private HashMap<Integer, Integer> id2Port;

	public Configuration(String configFile) throws Exception {
		id2Ip = new HashMap<Integer, String>();
		id2Port = new HashMap<Integer, Integer>();
		failNodes = new Vector<Integer>();
		Scanner cin = new Scanner(new File(configFile));
		String line = null;
		int type = -1;
		while ((line = readLine(cin)) != null) {
			if (line.startsWith("NS")) {
				ns = Integer.parseInt(line.substring(line.indexOf('=') + 1));
			} else if (line.startsWith("NC")) {
				nc = Integer.parseInt(line.substring(line.indexOf('=') + 1));
			} else if (line.startsWith("M")) {
				m = Integer.parseInt(line.substring(line.indexOf('=') + 1));
			} else if (line.startsWith("TIME_UNIT")) {
				timeUnit = Integer
						.parseInt(line.substring(line.indexOf('=') + 1));
			} else if (line.startsWith("SOCKINFO")) {
				type = 1;
			} else if (line.startsWith("FAIL")) {
				type = 2;
			} else if (type == 1) {
				StringTokenizer st = new StringTokenizer(line);
				int nodeId = Integer.parseInt(st.nextToken());
				String ip = InetAddress.getByName(st.nextToken())
						.getHostAddress();
				int port = Integer.parseInt(st.nextToken());
				id2Ip.put(nodeId, ip);
				id2Port.put(nodeId, port);
			} else if (type == 2) {
				StringTokenizer st = new StringTokenizer(line);
				while (st.hasMoreTokens()) {
					failNodes.add(Integer.parseInt(st.nextToken()));
				}
			}
		}
		LogUtils.debugLog("NS: " + ns);
		LogUtils.debugLog("NC: " + nc);
		LogUtils.debugLog("M: " + m);
		LogUtils.debugLog("TIME_UNIT: " + timeUnit);
		LogUtils.debugLog("SOCKINFO:");
		for (int nodeId : id2Ip.keySet()) {
			LogUtils.debugLog(nodeId + " " + id2Ip.get(nodeId) + " "
					+ id2Port.get(nodeId));
		}
		LogUtils.debugLog("FAILINGNODES:");
		for (int nodeId : failNodes) {
			LogUtils.debugLog("" + nodeId);
		}
	}

	private String readLine(Scanner cin) {
		if (cin.hasNextLine()) {
			String line = cin.nextLine();
			int idx = line.indexOf('#');
			if (idx == -1) {
				idx = line.length();
			}
			line = line.substring(0, idx).trim();
			if (line.equals("")) {
				return readLine(cin);
			} else {
				return line;
			}
		}
		return null;
	}

	public int getNS() {
		return ns;
	}

	public int getNC() {
		return nc;
	}

	public int getM() {
		return m;
	}

	public int getTimeUnit() {
		return timeUnit;
	}

	public Vector<Integer> getFailNodes() {
		return failNodes;
	}

	public String getIpAddress(int nodeId) {
		return id2Ip.get(nodeId);
	}

	public int getPort(int nodeId) {
		return id2Port.get(nodeId);
	}

	// public int getNodeIdByIp(String ipAddress) throws AosException {
	// for (Integer nodeId : id2Ip.keySet()) {
	// if (id2Ip.get(nodeId).equals(ipAddress)) {
	// return nodeId;
	// }
	// }
	// throw new AosException("getNodeIdByIp failed: " + ipAddress);
	// }

	public int getLocalNodeId() throws AosException {

		Vector<InetAddress> ips = new Vector<InetAddress>();

		Enumeration<NetworkInterface> netInterfaces = null;
		try {
			netInterfaces = NetworkInterface.getNetworkInterfaces();
			while (netInterfaces.hasMoreElements()) {
				NetworkInterface ni = netInterfaces.nextElement();
				Enumeration<InetAddress> ip = ni.getInetAddresses();
				while (ip.hasMoreElements()) {
					ips.add(ip.nextElement());
				}
			}
			String localHostIpList = "";
			for (InetAddress ip : ips) {
				localHostIpList += ip.getHostAddress() + "/";
			}
			LogUtils.debugLog("localHostIpList: " + localHostIpList);
		} catch (SocketException e) {
			LogUtils.errorLog(e.getMessage());
			throw new AosException(e.getMessage(), e);
		}
		LogUtils.runLog("InetAddress:getAllByName success");
		for (Integer id : id2Ip.keySet()) {
			for (InetAddress inet : ips) {
				if (inet.getHostAddress().equals(id2Ip.get(id))) {
					LogUtils.runLog("find localhost id success: " + id);
					return id;
				}
			}
		}
		LogUtils.runLog("find localhost id failed");
		throw new AosException("getLocalNodeId failed");
	}

}
